import crypto from 'crypto';
import { Logger, AppError, ErrorCode } from '../utils/logger';

// NASKI支付配置接口
export interface NaskiPayConfig {
  merchantId: string;      // 商户号
  secretKey: string;       // 密钥(用于签名)
  baseUrl: string;         // API基础URL
  notifyUrl: string;       // 回调通知URL
  publicKey?: string;      // RSA公钥(用于验证回调签名)
}

// 创建充值订单请求参数
export interface CreateNaskiOrderRequest {
  userId: number;
  amount: number;
  paymentMethod: 'BankTransfer' | 'qrPay';
  orderId: string;
  transAccNo: string;         // 付款银行卡号(必填)
  paymentName: string;        // 付款人真实名称(必填)
  bankCode?: string;          // 银行编码(可选)
  customerEmail?: string;     // 客户邮箱
  customerPhone?: string;     // 客户手机号
  extendParam?: string;       // 透传参数
}

// NASKI充值订单响应
export interface NaskiOrderResponse {
  code: number;               // 接口状态码(200表示请求成功)
  msg: string;                // 接口状态信息
  data?: {
    merOrderNo: string;       // 商户订单号(原样返回)
    orderNo: string;          // 平台订单号
    subCode: string;          // 业务错误码
    subMsg: string;           // 业务错误信息
    status: number;           // 订单状态(2=待支付,3=失败)
    orderData: string;        // 下单成功时有值(支付链接或二维码)
    common: string;           // 扩展参数
    sign: string;             // 数字签名
  };
}

// NASKI订单查询响应
export interface NaskiQueryResponse {
  code: number;               // 接口状态码(200表示请求成功)
  msg: string;                // 接口状态信息
  data?: {
    merOrderNo: string;       // 商户号
    orderNo: string;          // 平台订单号
    orderAmount: string;      // 订单金额
    payAmount: string;        // 支付金额
    busiCode: string;         // 支付编码
    status: number;           // 订单状态(5=成功,4=关闭,2=待支付,3=失败)
    payTime: string;          // 交易时间
    sign: string;             // 签名
  };
}

// NASKI回调通知数据
export interface NaskiNotification {
  merOrderNo: string;         // 商户订单号
  orderNo: string;            // 平台订单号
  status: number;             // 订单状态
  amount: string;             // 订单金额
  currency: string;           // 币种
  subCode?: string;           // 业务错误码
  subMsg?: string;            // 业务错误信息
  common?: string;            // 扩展参数
  sign: string;               // RSA签名
}

// 泰国银行代码映射到NASKI的busiCode
const BANK_CODE_TO_BUSI_CODE: Record<string, string> = {
  // 泰国网银
  '002': '102001', // Bangkok Bank - 泰国网银
  '004': '102001', // Kasikorn Bank - 泰国网银
  '006': '102001', // Krung Thai Bank - 泰国网银
  '011': '102001', // TMB Bank - 泰国网银
  '014': '102001', // Siam Commercial Bank - 泰国网银
  '025': '102001', // Bank of Ayudhya - 泰国网银

  // 泰国扫码
  '102002': '102002', // 泰国扫码

  // TrueMoney
  '102003': '102003', // 泰国TrueMoney

  // promptpay
  '102004': '102004', // 泰国promptpay

  // 泰国卡卡
  '102005': '102005', // 泰国卡卡
};

export class NaskiPayService {
  private config: NaskiPayConfig;

  constructor(config: NaskiPayConfig) {
    this.config = config;
  }

  /**
   * 生成订单号
   */
  generateOrderId(): string {
    const timestamp = Date.now();
    const random = Math.random().toString(36).substring(2, 8).toUpperCase();
    return `NASKI${timestamp}${random}`;
  }

  /**
   * 将银行代码转换为NASKI的busiCode
   */
  private getBusiCode(bankCode: string | undefined, paymentMethod: 'BankTransfer' | 'qrPay'): string {
    // 如果提供了bankCode并且在映射表中,使用映射值
    if (bankCode && BANK_CODE_TO_BUSI_CODE[bankCode]) {
      return BANK_CODE_TO_BUSI_CODE[bankCode];
    }

    // 否则根据支付方式使用默认值
    switch (paymentMethod) {
      case 'qrPay':
        return '102002'; // 泰国扫码
      case 'BankTransfer':
        return '102001'; // 泰国网银
      default:
        return '102002'; // 默认使用扫码
    }
  }

  /**
   * 生成HmacSHA256签名
   * 签名规则:
   * 1. 将有数据按照字段名的ASCII码从小到大排序(字典序)
   * 2. 使用QueryString格式(key1=value1&key2=value2...)拼接成字符串
   * 3. 空参数不参与签名
   * 4. 使用HmacSHA256对字符串加密
   */
  private generateSign(params: Record<string, any>): string {
    try {
      // 1. 过滤空值并按ASCII码排序
      const filteredParams: Record<string, string> = {};
      for (const [key, value] of Object.entries(params)) {
        if (value !== null && value !== undefined && value !== '' && key !== 'sign') {
          filteredParams[key] = String(value);
        }
      }

      // 2. 按字典序排序
      const sortedKeys = Object.keys(filteredParams).sort();

      // 3. 拼接字符串
      const stringA = sortedKeys.map(key => `${key}=${filteredParams[key]}`).join('&');

      Logger.debug('NASKI签名原始字符串', { stringA });

      // 4. HmacSHA256加密
      const sign = crypto
        .createHmac('sha256', this.config.secretKey)
        .update(stringA, 'utf8')
        .digest('hex');

      Logger.debug('NASKI签名生成', { sign });

      return sign;
    } catch (error) {
      Logger.error('NASKI签名生成失败', error);
      throw new AppError('签名生成失败', ErrorCode.PAYMENT_SIGN_ERROR);
    }
  }

  /**
   * 验证回调签名(使用HmacSHA256,与下单时相同的签名方式)
   */
  verifyNotification(data: any): boolean {
    if (!data.sign) {
      Logger.warn('NASKI回调通知缺少签名');
      return false;
    }

    try {
      const receivedSign = data.sign;

      // 按照下单时的规则生成待验签字符串
      // 1. 过滤空值和sign字段
      const filteredParams: Record<string, string> = {};
      for (const [key, value] of Object.entries(data)) {
        if (value !== null && value !== undefined && value !== '' && key !== 'sign') {
          filteredParams[key] = String(value);
        }
      }

      // 2. 按字典序排序
      const sortedKeys = Object.keys(filteredParams).sort();

      // 3. 拼接字符串
      const stringToVerify = sortedKeys.map(key => `${key}=${filteredParams[key]}`).join('&');

      Logger.debug('NASKI回调验签字符串', { stringToVerify });

      // 4. 使用HmacSHA256计算签名
      const expectedSign = crypto
        .createHmac('sha256', this.config.secretKey)
        .update(stringToVerify, 'utf8')
        .digest('hex');

      const isValid = receivedSign === expectedSign;

      Logger.info('NASKI回调签名验证', {
        isValid,
        receivedSign: receivedSign.substring(0, 20) + '...',
        expectedSign: expectedSign.substring(0, 20) + '...'
      });

      return isValid;
    } catch (error) {
      Logger.error('NASKI回调签名验证出错', error);
      return false;
    }
  }

  /**
   * 创建充值订单(代收)
   */
  async createRechargeOrder(request: CreateNaskiOrderRequest): Promise<NaskiOrderResponse> {
    Logger.info('NASKI创建充值订单', {
      orderId: request.orderId,
      amount: request.amount,
      paymentMethod: request.paymentMethod,
      paymentName: request.paymentName,
      transAccNo: request.transAccNo
    });

    // 获取busiCode
    const busiCode = this.getBusiCode(request.bankCode, request.paymentMethod);

    // 构建充值请求参数
    const orderParams = {
      bankCode: request.bankCode || '',     // 银行编码(可选)
      name: request.paymentName,            // 付款人姓名(必填)
      merNo: this.config.merchantId,        // 商户号(必填)
      merOrderNo: request.orderId,          // 商户订单号(必填)
      email: request.customerEmail || 'customer@naski.com', // 邮箱(必填)
      phone: request.customerPhone || '0000000000',         // 手机号(必填)
      orderAmount: request.amount.toString(), // 订单金额(必填)
      currency: 'THB',                      // 币种(必填)
      busiCode: busiCode,                   // 支付类型编码(必填)
      pageUrl: this.config.notifyUrl,       // 支付成功跳转地址(必填)
      notifyUrl: this.config.notifyUrl,     // 通知地址(必填)
      timestamp: Date.now().toString(),     // 时间戳(必填,5分钟内有效)
    };

    // 生成签名
    const sign = this.generateSign(orderParams);
    const requestData = { ...orderParams, sign };

    const fullUrl = `${this.config.baseUrl}/payin/createOrder`;

    Logger.info('NASKI发送充值请求', {
      orderId: request.orderId,
      url: fullUrl,
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: requestData,
      bodySize: JSON.stringify(requestData).length
    });

    try {
      const response = await fetch(fullUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'User-Agent': 'TaiGuoChongZhiSystem/1.0'
        },
        body: JSON.stringify(requestData),
        signal: AbortSignal.timeout(30000), // 30秒超时
      });

      Logger.info('NASKI充值响应状态', {
        orderId: request.orderId,
        status: response.status,
        statusText: response.statusText,
        headers: Object.fromEntries(response.headers.entries())
      });

      if (!response.ok) {
        let errorText = '';
        try {
          errorText = await response.text();
          Logger.error('NASKI充值API错误响应', {
            orderId: request.orderId,
            status: response.status,
            responseText: errorText
          });
        } catch (e) {
          Logger.error('无法读取NASKI充值错误响应', e);
        }

        throw new AppError(
          `NASKI充值API请求失败: ${response.status} - ${errorText}`,
          ErrorCode.PAYMENT_API_ERROR
        );
      }

      const result: NaskiOrderResponse = await response.json();

      Logger.info('NASKI充值订单响应', {
        orderId: request.orderId,
        response: result
      });

      return result;
    } catch (error) {
      Logger.error('NASKI创建充值订单失败', error, {
        orderId: request.orderId,
        amount: request.amount
      });

      if (error instanceof AppError) {
        throw error;
      }

      throw new AppError('NASKI充值接口调用失败', ErrorCode.PAYMENT_API_ERROR, {
        orderId: request.orderId
      });
    }
  }

  /**
   * 查询订单状态
   */
  async queryOrder(orderId: string, platOrderNum?: string): Promise<NaskiQueryResponse> {
    Logger.info('NASKI查询订单', { orderId, platOrderNum });

    // 生成唯一请求流水号
    const requestNo = `REQ${Date.now()}${Math.random().toString(36).substring(2, 8).toUpperCase()}`;

    const queryParams: Record<string, string> = {
      merNo: this.config.merchantId,
      requestNo: requestNo,           // 请求流水号
      timestamp: Date.now().toString(),
    };

    // 添加订单号参数(商户订单号或平台订单号至少提供一个)
    if (orderId) {
      queryParams.merOrderNo = orderId;
    }
    if (platOrderNum) {
      queryParams.orderNo = platOrderNum;
    }

    const sign = this.generateSign(queryParams);
    const requestData = { ...queryParams, sign };

    const fullUrl = `${this.config.baseUrl}/payin/orderQuery`;

    Logger.info('NASKI发送查询请求', {
      orderId,
      platOrderNum,
      url: fullUrl,
      requestNo,
    });

    try {
      const response = await fetch(fullUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'User-Agent': 'TaiGuoChongZhiSystem/1.0'
        },
        body: JSON.stringify(requestData),
        signal: AbortSignal.timeout(30000),
      });

      if (!response.ok) {
        throw new AppError(
          `NASKI查询API请求失败: ${response.status}`,
          ErrorCode.PAYMENT_API_ERROR
        );
      }

      const result: NaskiQueryResponse = await response.json();

      Logger.info('NASKI查询订单响应', {
        orderId,
        response: result
      });

      return result;
    } catch (error) {
      Logger.error('NASKI查询订单失败', error, { orderId });
      throw new AppError('NASKI查询接口调用失败', ErrorCode.PAYMENT_API_ERROR, {
        orderId
      });
    }
  }

  /**
   * 解析订单状态
   */
  parseOrderStatus(status: number): string {
    switch (status) {
      case 5:
        return 'SUCCESS';        // 成功
      case 4:
        return 'CLOSED';         // 关闭
      case 2:
        return 'PENDING';        // 待支付
      case 3:
        return 'FAILED';         // 失败
      default:
        return 'UNKNOWN';
    }
  }
}

/**
 * 检查NASKI是否已配置
 */
export function isNaskiConfigured(): boolean {
  return !!(
    process.env.NASKI_MERCHANT_ID &&
    process.env.NASKI_SECRET_KEY &&
    process.env.NASKI_BASE_URL
  );
}

/**
 * 创建NASKI服务实例
 */
export function createNaskiPayService(): NaskiPayService {
  if (!isNaskiConfigured()) {
    throw new AppError('NASKI配置不完整', ErrorCode.PAYMENT_CONFIG_ERROR);
  }

  const config: NaskiPayConfig = {
    merchantId: process.env.NASKI_MERCHANT_ID!,
    secretKey: process.env.NASKI_SECRET_KEY!,
    baseUrl: process.env.NASKI_BASE_URL!,
    notifyUrl: process.env.NASKI_NOTIFY_URL || '',
    publicKey: process.env.NASKI_PUBLIC_KEY, // RSA公钥(可选,用于验证回调)
  };

  return new NaskiPayService(config);
}